﻿
using System;
using System.IO;
using System.Linq;
using System.Text;

namespace CatEars.Core.FileFormat.Ini
{
    /// <summary>
    /// Ini文件格式
    /// </summary>
    public static class IniFormater
    {
        /// <summary>
        /// 从文件解析
        /// </summary>
        /// <param name="strFilePath"></param>
        /// <param name="define"></param>
        public static IniFile LoadFromFile(string strFilePath, IniDefine define = null)
        {
            return new IniFile(strFilePath, define);
        }

        /// <summary>
        /// 从文件解析
        /// </summary>
        /// <param name="strText"></param>
        /// <param name="define"></param>
        public static IniFile LoadFromText(string strText, IniDefine define = null)
        {
            var entity = new IniFile();
            LoadFromText(entity, strText, define);
            return entity;
        }

        #region 读操作

        /// <summary>
        /// 从文件解析
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="strText"></param>
        /// <param name="define"></param>
        static void LoadFromText(IniFile entity, string strText, IniDefine define = null)
        {
            if (define == null) define = entity.IniDefine;
            if (define == null) define = IniDefine.Default;
            var enc = define.GetEncoding();
            if (enc == null) enc = Encoding.UTF8;
            using (var ms = enc.GetBytes(strText).ToMemoryStream())
            {
                StreamReader sr = new StreamReader(ms, enc);
                using (sr)
                {
                    LoadFromSR(entity, sr, define);
                }
            }
        }

        /// <summary>
        /// 从文件解析
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="strFilePath"></param>
        /// <param name="define"></param>
        internal static void LoadFromFile(IniFile entity, string strFilePath, IniDefine define = null)
        {
            if (define == null) define = entity.IniDefine;
            if (define == null) define = IniDefine.Default;
            StreamReader sr;
            if (define.GetEncoding() != null) sr = new StreamReader(strFilePath, define.GetEncoding());
            else sr = new StreamReader(strFilePath);
            using (sr)
            {
                LoadFromSR(entity, sr, define);
            }
        }

        /// <summary>
        /// 从文件解析
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="sr"></param>
        /// <param name="define"></param>
        static void LoadFromSR(IniFile entity, StreamReader sr, IniDefine define)
        {
            int intRowIndex = 0;
            var section = entity.DefaultSection;
            while (true)
            {
                string strLine = sr.ReadLine();
                if (strLine == null)
                {
                    break;
                }
                intRowIndex++;
                try
                {
                    //空行或者注释行
                    if (string.IsNullOrWhiteSpace(strLine)
                        || define.IgnoreRowStart.Contains(strLine[0]))
                    {
                        section.AddText(strLine);
                        continue;
                    }
                    string strLine0 = strLine.Trim();
                    if (strLine0[0] == '[' && strLine0[strLine0.Length - 1] == ']')
                    {
                        string strSectionName = strLine0.Substring(1, strLine0.Length - 2);
                        //添加一个新的Section
                        section = entity.AddSection(strSectionName);
                        continue;
                    }
                    int intIndexChar = strLine.IndexOf('=');
                    if (intIndexChar > 0)
                    {
                        string strKey = strLine.Substring(0, intIndexChar);
                        string strValue = strLine.Substring(intIndexChar + 1);
                        section.Set(strKey, strValue);
                        continue;
                    }
                    else
                    {
                        throw new FormatException(
                            string.Format("第{0}行“{1}”附近有错误:未能识别的格式", intRowIndex, strLine));
                    }
                }
                catch (FormatException)
                {
                    throw;
                }
                catch (Exception exc)
                {
                    throw new FormatException(
                        string.Format("第{0}行“{1}”附近有错误:{2}", intRowIndex, strLine, exc.Message), exc);
                }
            }
            entity.IniDefine = define;
        }

        #endregion

        #region 写操作

        /// <summary>
        /// 写入到文件
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="strFilePath"></param>
        /// <param name="define"></param>
        public static void SaveToFile(IniFile entity, string strFilePath, IniDefine define = null)
        {
            StreamWriter sw;
            if (define == null) define = entity.IniDefine;
            if (define == null) define = IniDefine.Default;
            if (define.GetEncoding() != null) sw = new StreamWriter(strFilePath, false, define.GetEncoding());
            else sw = new StreamWriter(strFilePath);
            using (sw)
            {
                sw.NewLine = define.NewLine;
                foreach (var item in entity.SectionNames)
                {
                    var sec = entity[item];
                    if (sec.Name != "")
                    {
                        sw.WriteLine("[" + sec.Name + "]");
                    }
                    foreach (var row in sec.AllRows)
                    {
                        if (row.Length == 0)
                        {
                            sw.WriteLine(row);
                        }
                        else if (row[0] == '[' && row[row.Length - 1] == ']')
                        {
                            string strKey = row.Substring(1, row.Length - 2);
                            string strValue = sec[strKey];
                            sw.WriteLine("{0}={1}", strKey, strValue);
                        }
                        else
                        {
                            if (!define.IgnoreRowStart.Contains(row[0]))
                            {
                                sw.WriteLine(define.IgnoreRowStart[0]);
                            }
                            sw.WriteLine(row);
                        }
                    }
                }
            }
        }

        #endregion
    }
}
